
#include <sstream>

#include <boost/algorithm/string/trim.hpp>

#include "broker.hpp"


namespace	sakcab	{
namespace	client	{

Broker::Broker( std::string host, std::string port )
	:	_host(host), _port(port), _connected(false), END_TAG("\r\n"),
        _socket( _io_service )
{
}

Broker::~Broker()
{
	this->disconnect();
}

int	
Broker::call( const std::string& request, std::string& response )
{
	this->connect();

	try {
			std::ostringstream  request_stream;
			request_stream << request << END_TAG;
			std::string request_str = request_stream.str();

			boost::asio::write(_socket, boost::asio::buffer(request_str.c_str(), request_str.size()) );

            boost::asio::streambuf response_streambuf;
            boost::asio::read_until(_socket, response_streambuf, "\r\n");
	
            std::istream _stream( &response_streambuf );
            std::getline( _stream, response );
            boost::trim( response );
	}
    catch (std::exception& e)
    {
		this->disconnect();


		std::ostringstream	msg;
		msg << "fail to communicate with TCP://" << _host << ":" << _port << "(request-size:" << request.size() << ") -- " << e.what();
		throw std::runtime_error( msg.str() );
	}

	return 0;
}


///////////////////////////////////////////////////////////////////////
//

int	
Broker::connect()
{
	if (_connected) {
		return 0;
	}

	try {
        boost::asio::ip::tcp::resolver resolver( _io_service );
        //boost::asio::ip::tcp::resolver::query query(tcp::v4(), _host, _port);
        boost::asio::ip::tcp::resolver::query query( _host, _port );
        boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
		boost::asio::ip::tcp::resolver::iterator end;

        boost::system::error_code error = boost::asio::error::host_not_found;
        while (error && iterator != end) {
            _socket.close();
            _socket.connect(*iterator++, error);
        }   
        if (error) {
            throw boost::system::system_error(error);
        }   
	}
    catch (std::exception& e)
    {
		boost::system::error_code ignored_ec;
		_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);

		std::ostringstream	msg;
		msg << "fail to connect to TCP://" << _host << ":" << _port << " -- " << e.what();
		throw std::runtime_error( msg.str() );
	}

	_connected = true;

	return	0;
}

int	
Broker::disconnect()
{
	if (!_connected) {
		return 0;
	}

	boost::system::error_code ignored_ec;
	_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);

	_connected = false;
	return	0;
}


}	//// namespace client
}	//// namespace sakcab


